package com.aiyige.page.my.download.service;

import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;

import com.aiyige.R;
import com.aiyige.base.db.dao.DownloadFileDao;
import com.aiyige.base.db.dao.DownloadModelDao;
import com.aiyige.base.db.table.DownloadFile;
import com.aiyige.base.db.table.DownloadModel;
import com.aiyige.page.my.download.util.DownloadUtil;
import com.aiyige.utils.AccountUtil;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.UpdateBuilder;
import com.j256.ormlite.stmt.Where;
import com.liulishuo.filedownloader.BaseDownloadTask;
import com.liulishuo.filedownloader.FileDownloadLargeFileListener;
import com.liulishuo.filedownloader.FileDownloadListener;
import com.liulishuo.filedownloader.FileDownloader;

import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import timber.log.Timber;

public class DownloadService extends Service {
    public DownloadService() {
    }

    Dao<DownloadModel, String> downloadModelDao;
    Dao<DownloadFile, Integer> downloadFileDao;

    ScanThread scanThread;
    Handler mainHandler = null;
    Notification downloadServiceNotification;
    public static final int DOWNLOAD_SERVICE_NOTIFICATION_ID = 11;
    volatile boolean firstRun = true;
    FileDownloadListener fileDownloadListener;
    volatile boolean shouldSendDownloadUpdateBroadcast = false;
    volatile boolean shouldSendDownloadProgressStatusUpadteBroadcast = false;
    volatile int downloadingFileNum = 0;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        firstRun = true;
        downloadingFileNum = 0;
        downloadModelDao = DownloadModelDao.getDao();
        downloadFileDao = DownloadFileDao.getDao();
        mainHandler = new Handler(Looper.getMainLooper());
        downloadServiceNotification = new Notification.Builder(this)
                .setOngoing(true)
                .setTicker(getString(R.string.downloading))
                .setContentTitle(getString(R.string.aiyige_download_service))
                .setContentText(getString(R.string.downloading))
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .build();
        //startForeground(DOWNLOAD_SERVICE_NOTIFICATION_ID, downloadServiceNotification);
        DownloadUtil.createStage();
        FileDownloader.getImpl().bindService(new Runnable() {
            @Override
            public void run() {
                FileDownloader.getImpl().setMaxNetworkThreadCount(DownloadUtil.MAX_DOWNLOAD_THREAD);
            }
        });
        FileDownloader.setGlobalPost2UIInterval(300);
        fileDownloadListener = new FileDownloadLargeFileListener() {
            @Override
            protected void completed(BaseDownloadTask task) {
                Timber.e("completed:");
                try {
                    UpdateBuilder<DownloadFile, Integer> updateBuilder = downloadFileDao.updateBuilder();
                    updateBuilder.updateColumnValue(DownloadFile.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED);
                    updateBuilder.updateColumnValue(DownloadFile.DOWNLOAD_TIMESTAMP_FIELD, System.currentTimeMillis());
                    updateBuilder.updateColumnValue(DownloadFile.FILE_LOCAL_URL, task.getTargetFilePath());
                    updateBuilder.where().eq(DownloadFile.ID_FIELD, task.getTag());
                    updateBuilder.update();
                    shouldSendDownloadUpdateBroadcast = true;
                    downloadingFileNum--;
                } catch (Exception e) {
                    Timber.e("completed:" + Log.getStackTraceString(e));
                }
            }

            @Override
            protected void error(BaseDownloadTask task, Throwable e) {
                Timber.e("error:");
                downloadingFileNum--;
            }

            @Override
            protected void warn(BaseDownloadTask task) {
                Timber.e("warn:");
            }

            @Override
            protected void pending(BaseDownloadTask task, long soFarBytes, long totalBytes) {
                Timber.e("pending:");
            }

            @Override
            protected void progress(BaseDownloadTask task, long soFarBytes, long totalBytes) {
                Timber.e("progress:" + (float) soFarBytes / totalBytes);
                try {
                    UpdateBuilder<DownloadFile, Integer> updateBuilder = downloadFileDao.updateBuilder();
                    updateBuilder.updateColumnValue(DownloadFile.DOWNLOADED_SIZE_FIELD, soFarBytes);
                    updateBuilder.updateColumnValue(DownloadFile.TOTAL_SIZE, totalBytes);
                    updateBuilder.updateColumnValue(DownloadFile.DOWNLOAD_TIMESTAMP_FIELD, System.currentTimeMillis());
                    updateBuilder.where().eq(DownloadFile.ID_FIELD, task.getTag());
                    updateBuilder.update();
                    shouldSendDownloadUpdateBroadcast = true;
                } catch (SQLException e) {
                    Timber.e("progress:" + Log.getStackTraceString(e));
                }
            }

            @Override
            protected void paused(BaseDownloadTask task, long soFarBytes, long totalBytes) {
                Timber.e("paused:");
                downloadingFileNum--;
            }
        };
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (!AccountUtil.isLogin()) return START_NOT_STICKY;
        if (firstRun) {
            firstRun = false;
            scanThread = new ScanThread();
            scanThread.start();
        }
        return START_STICKY;
    }

    public static void startDownload(Context context) {
        context.startService(new Intent(context, DownloadService.class));
    }

    @Override
    public void onDestroy() {
        downloadingFileNum = 0;
        FileDownloader.getImpl().pauseAll();
        if (scanThread != null) {
            scanThread.shutdown();
        }
        super.onDestroy();
    }

    public void sendDownloadUpdateBroadcast() {
        mainHandler.post(new Runnable() {
            @Override
            public void run() {
                DownloadUtil.sendDownloadUpdateBroadcast();
            }
        });
    }

    public void sendDownloadProgressStatusUpdateBroadcast() {
        mainHandler.post(new Runnable() {
            @Override
            public void run() {
                DownloadUtil.sendDownloadProgressStatusUpdateBroadcast();
            }
        });
    }


    public class ScanThread extends Thread {
        public final String TAG = ScanThread.class.getSimpleName();
        volatile boolean stopWork = false;
        Lock mutex = new ReentrantLock();
        Condition waitCondition = mutex.newCondition();


        public ScanThread() {
        }

        @Override
        public void run() {
            while (true) {
                mutex.lock();
                if (stopWork) {
                    mutex.unlock();
                    break;
                }
                if (AccountUtil.isLogin()) {
                    handleBroadcast();
                    handleDelete();
                    handleDownloadCover();
                    handlePause();
                    handleDownload();
                    handleDownloadFinish();
                    if (checkFinish()) {
                        stopSelf();
                    }
                }
                try {
                    waitCondition.await(DownloadUtil.SCAN_INTERVAL_MS, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mutex.unlock();
            }
            handleBroadcast();
        }

        public void handleBroadcast() {
            if (shouldSendDownloadUpdateBroadcast) {
                sendDownloadUpdateBroadcast();
                shouldSendDownloadUpdateBroadcast = false;
            }

            if (shouldSendDownloadProgressStatusUpadteBroadcast) {
                sendDownloadProgressStatusUpdateBroadcast();
                shouldSendDownloadProgressStatusUpadteBroadcast = false;
            }
        }

        public void handlePause() {
            try {
                List<DownloadFile> downloadFileList = downloadFileDao.queryBuilder()
                        .where()
                        .eq(DownloadFile.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_PAUSE)
                        .and()
                        .eq(DownloadFile.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOADING)
                        .query();
                for (DownloadFile downloadFile : downloadFileList) {
                    FileDownloader.getImpl().pause(downloadFile.getDownloadId());
                    UpdateBuilder<DownloadFile, Integer> updateBuilder = downloadFileDao.updateBuilder();
                    updateBuilder.updateColumnValue(DownloadFile.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_WAITING_DOWNLOAD);
                    updateBuilder.where().eq(DownloadFile.ID_FIELD, downloadFile.getId());
                    updateBuilder.update();
                }
            } catch (Exception e) {

            }
        }

        public void handleDownloadCover() {
            try {
                QueryBuilder<DownloadModel, String> queryBuilder = downloadModelDao.queryBuilder();
                Where<DownloadModel, String> where = queryBuilder.where();
                where.and(
                        where.eq(DownloadModel.USER_ID_FIELD, AccountUtil.getCurrentUser().getId())
                                .and()
                                .ne(DownloadModel.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE)
                                .and()
                                .ne(DownloadModel.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE_RECORD_ONLY),
                        where.eq(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_WAITING_DOWNLOAD_COVER)
                                .or()
                                .eq(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_COVER_FAILED)
                );
                List<DownloadModel> downloadModelList = queryBuilder.query();
                for (DownloadModel downloadModel : downloadModelList) {
                    boolean downloadCoverSuccess = true;
                    try {
                        downloadModel.setCoverLocalUrl(DownloadUtil.downloadCover(downloadModel.getCoverRemoteUrl()));
                    } catch (Exception e) {
                        //downloadCoverSuccess = false;//目前不强求封面一定下载成功
                    }
                    if (downloadCoverSuccess) {
                        UpdateBuilder<DownloadModel, String> updateBuilder = downloadModelDao.updateBuilder();
                        updateBuilder.updateColumnValue(DownloadModel.COVER_LOCAL_URL, downloadModel.getCoverLocalUrl());
                        updateBuilder.updateColumnValue(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_WAITING_DOWNLOAD);
                        updateBuilder.where().eq(DownloadModel.ID_FIELD, downloadModel.getId());
                        updateBuilder.update();
                    } else {
                        UpdateBuilder<DownloadModel, String> updateBuilder = downloadModelDao.updateBuilder();
                        updateBuilder.updateColumnValue(DownloadModel.COVER_LOCAL_URL, "");
                        updateBuilder.updateColumnValue(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_COVER_FAILED);
                        updateBuilder.where().eq(DownloadModel.ID_FIELD, downloadModel.getId());
                        updateBuilder.update();
                    }
                }
            } catch (Exception e) {
                Timber.e("handleDownloadCover:" + Log.getStackTraceString(e));
            }

            try {
                QueryBuilder<DownloadFile, Integer> queryBuilder = downloadFileDao.queryBuilder();
                Where<DownloadFile, Integer> where = queryBuilder.where();
                where.and(
                        where.eq(DownloadModel.USER_ID_FIELD, AccountUtil.getCurrentUser().getId())
                                .and()
                                .ne(DownloadModel.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE)
                                .and()
                                .ne(DownloadModel.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE_RECORD_ONLY),
                        where.eq(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_WAITING_DOWNLOAD_COVER)
                                .or()
                                .eq(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_COVER_FAILED)
                );

                List<DownloadFile> downloadFileList = queryBuilder.query();
                for (DownloadFile downloadFile : downloadFileList) {
                    boolean downloadCoverSuccess = true;
                    try {
                        downloadFile.setCoverLocalUrl(DownloadUtil.downloadCover(downloadFile.getCoverRemoteUrl()));
                    } catch (Exception e) {
                        //downloadCoverSuccess = false;//目前不强求封面一定要下载成功
                    }
                    if (downloadCoverSuccess) {
                        UpdateBuilder<DownloadFile, Integer> updateBuilder = downloadFileDao.updateBuilder();
                        updateBuilder.updateColumnValue(DownloadFile.COVER_LOCAL_URL, downloadFile.getCoverLocalUrl());
                        updateBuilder.updateColumnValue(DownloadFile.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_WAITING_DOWNLOAD);
                        updateBuilder.where().eq(DownloadFile.ID_FIELD, downloadFile.getId());
                        updateBuilder.update();
                    } else {
                        UpdateBuilder<DownloadFile, Integer> updateBuilder = downloadFileDao.updateBuilder();
                        updateBuilder.updateColumnValue(DownloadFile.COVER_LOCAL_URL, "");
                        updateBuilder.updateColumnValue(DownloadFile.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_COVER_FAILED);
                        updateBuilder.where().eq(DownloadFile.ID_FIELD, downloadFile.getId());
                        updateBuilder.update();
                    }
                }
            } catch (Exception e) {
                Timber.e("handleDownloadCover:" + Log.getStackTraceString(e));
            }
        }


        public void handleDownload() {
            if (downloadingFileNum >= DownloadUtil.MAX_DOWNLOAD_THREAD) {
                return;
            }
            List<DownloadFile> downloadFileList = new LinkedList<>();
            try {
                downloadFileList = downloadFileDao.queryBuilder()
                        .where()
                        .eq(DownloadFile.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DOWNLOAD)
                        .and()
                        .eq(DownloadFile.USER_ID_FIELD, AccountUtil.getCurrentUser().getId())
                        .query();
            } catch (Exception e) {

            }
            for (DownloadFile downloadFile : downloadFileList) {
                switch (downloadFile.getProgressStatus()) {
                    case DownloadUtil.PROGRESS_STATUS_WAITING_DOWNLOAD:
                    case DownloadUtil.PROGRESS_STATUS_DOWNLOADING: {
                        if ((System.currentTimeMillis() - downloadFile.getDownloadTimestamp()) > DownloadUtil.DOWNLOAD_IDLE_TIMEOUT_MS) {
                            retryDownloadFile(downloadFile);
                        }
                        break;
                    }
                }
            }
        }

        public void handleDownloadFinish() {
            try {
                List<DownloadModel> downloadModelList = downloadModelDao.queryBuilder()
                        .where()
                        .eq(DownloadModel.USER_ID_FIELD, AccountUtil.getCurrentUser().getId())
                        .and()
                        .ne(DownloadModel.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE)
                        .and()
                        .ne(DownloadModel.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE_RECORD_ONLY)
                        .and()
                        .ne(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_FAILED)
                        .and()
                        .ne(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED)
                        .query();
                for (DownloadModel downloadModel : downloadModelList) {
                    List<DownloadFile> downloadFileList = downloadFileDao.queryBuilder()
                            .where()
                            .eq(DownloadFile.PARENT_ID_FIELD, downloadModel.getId())
                            .and()
                            .ne(DownloadFile.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE)
                            .and()
                            .ne(DownloadFile.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE_RECORD_ONLY)
                            .and()
                            .ne(DownloadFile.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED)
                            .query();
                    if (downloadFileList.isEmpty()) {
                        UpdateBuilder<DownloadModel, String> updateBuilder = downloadModelDao.updateBuilder();
                        updateBuilder.updateColumnValue(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED);
                        updateBuilder.where().eq(DownloadModel.ID_FIELD, downloadModel.getId());
                        updateBuilder.update();
                        shouldSendDownloadProgressStatusUpadteBroadcast = true;
                    }
                }
            } catch (Exception e) {

            }
        }


        public void handleDelete() {
            try {
                List<DownloadFile> downloadFileList = downloadFileDao.queryForEq(DownloadFile.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE);
                for (DownloadFile downloadFile : downloadFileList) {
                    FileDownloader.getImpl().pause(downloadFile.getDownloadId());
                    downloadFileDao.deleteById(downloadFile.getId());
                    shouldSendDownloadProgressStatusUpadteBroadcast = true;
                }
            } catch (SQLException e) {
                Log.e(TAG, "handleDelete:" + Log.getStackTraceString(e));
            }
            try {
                List<DownloadModel> downloadModelList = downloadModelDao.queryForEq(DownloadModel.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE);
                for (DownloadModel downloadModel : downloadModelList) {
                    downloadModelDao.deleteById(downloadModel.getId());
                    shouldSendDownloadProgressStatusUpadteBroadcast = true;
                }
            } catch (Exception e) {
                Log.e(TAG, "handleDelete:" + Log.getStackTraceString(e));
            }

            try {
                List<DownloadFile> downloadFileList = downloadFileDao.queryForEq(DownloadFile.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE_RECORD_ONLY);
                for (DownloadFile downloadFile : downloadFileList) {
                    FileDownloader.getImpl().pause(downloadFile.getDownloadId());
                    downloadFileDao.deleteById(downloadFile.getId());
                    shouldSendDownloadProgressStatusUpadteBroadcast = true;
                }
            } catch (SQLException e) {
                Log.e(TAG, "handleDelete:" + Log.getStackTraceString(e));
            }
            try {
                List<DownloadModel> downloadModelList = downloadModelDao.queryForEq(DownloadModel.CONTROL_OPTION_FIELD, DownloadUtil.CONTROL_OPTION_DELETE_RECORD_ONLY);
                for (DownloadModel downloadModel : downloadModelList) {
                    downloadModelDao.deleteById(downloadModel.getId());
                    shouldSendDownloadProgressStatusUpadteBroadcast = true;
                }
            } catch (Exception e) {
                Log.e(TAG, "handleDelete:" + Log.getStackTraceString(e));
            }


        }

        public boolean checkFinish() {
            try {
                List<DownloadModel> downloadModelList = downloadModelDao.queryBuilder()
                        .where()
                        .eq(DownloadModel.USER_ID_FIELD, AccountUtil.getCurrentUser().getId())
                        .and()
                        .ne(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED)
                        .and()
                        .ne(DownloadModel.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOAD_FAILED)
                        .query();
                if (!downloadModelList.isEmpty()) {
                    return false;
                }
            } catch (Exception e) {
                Timber.e("handleDelete:" + Log.getStackTraceString(e));
            }
            return true;
        }

        public void retryDownloadFile(DownloadFile downloadFile) {
            try {
                UpdateBuilder<DownloadFile, Integer> updateBuilder = downloadFileDao.updateBuilder();
                updateBuilder.updateColumnValue(DownloadFile.DOWNLOAD_TIMESTAMP_FIELD, System.currentTimeMillis());
                updateBuilder.updateColumnValue(DownloadFile.PROGRESS_STATUS_FIELD, DownloadUtil.PROGRESS_STATUS_DOWNLOADING);
                updateBuilder.where().eq(DownloadFile.ID_FIELD, downloadFile.getId());
                updateBuilder.update();
            } catch (SQLException e) {
                Timber.e("retryDownloadFile:" + Log.getStackTraceString(e));
                return;
            }
            int downloadId = FileDownloader.getImpl()
                    .create(downloadFile.getFileRemoteUrl())
                    .setPath(downloadFile.getFileLocalUrl(), false)
                    .setTag(downloadFile.getId())
                    .setListener(fileDownloadListener)
                    .start();
            try {
                UpdateBuilder<DownloadFile, Integer> updateBuilder = downloadFileDao.updateBuilder();
                updateBuilder.updateColumnValue(DownloadFile.DOWNLOAD_ID, downloadId);
                updateBuilder.where().eq(DownloadFile.ID_FIELD, downloadFile.getId());
                updateBuilder.update();
                downloadingFileNum++;
            } catch (SQLException e) {
                Timber.e("retryDownloadFile:" + Log.getStackTraceString(e));
                FileDownloader.getImpl().pause(downloadId);
                return;
            }
        }

        public void shutdown() {
            mutex.lock();
            stopWork = true;
            waitCondition.signalAll();
            mutex.unlock();
            try {
                join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
